﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DataTreeLib;
using LiveSequence.Common.Domain;
using LiveSequence.Suite.Controllers;
using LiveSequence.Suite.Utils;
using LiveSequence.Suite.Views;

namespace LiveSequence.Suite.Dialogs
{
  public partial class DlgFilterMethodCallTree : Form
  {
    private const int ASSEMBLY_INDEX = 1;
    private const int NAMESPACE_INDEX = 2;
    private const int TYPE_INDEX = 3;
    private const int METHOD_INDEX = 4;

    private SequenceData _seqData;
    DTreeNode<object> _root;
    private TreeViewController<object> _treeViewController;
    private SearchingTreeViewController _searchingTreeViewController;

    public DlgFilterMethodCallTree(SequenceData data)
    {
      InitializeComponent();
      InitializeComponentEx();
      _seqData = data;

      List<MethodCallInfo> methodCallList = data.GetMethodList();
      populateMethodDiagramTreeView(methodCallList);

      _root = createMethodCallTree(methodCallList);
      _treeViewController = new TreeViewController<object>(_methodCallTreeView, _root, new FilterMethodCallTreeNodeMapper());
      
    }

    private void InitializeComponentEx()
    {
      _searchingTreeViewController = new SearchingTreeViewController(_treeViewFilters, _toolStripFilters);
      _searchingTreeViewController.SearchText += new EventHandler(_searchingTreeViewController_SearchText);
    }

    void _searchingTreeViewController_SearchText(object sender, EventArgs e)
    {
      string searchedText = _searchingTreeViewController.SearchedText;
      TreeNode tNode = TreeViewHelper.SearchTreeNode(_treeViewFilters, new TextTNodeComparer(searchedText));
      if (tNode != null)
      {
        tNode.EnsureVisible();
        _treeViewFilters.SelectedNode = tNode;
      }

    }

    private void populateMethodDiagramTreeView(List<MethodCallInfo> methodCallList)
    {
      foreach (MethodCallInfo methodCallInfo in methodCallList)
      {
        TreeNode assemblyNode = insertNode(_treeViewFilters.Nodes, methodCallInfo.TargetMethodAssembly, ASSEMBLY_INDEX);
        TreeNode nameSpaceNode = insertNode(assemblyNode.Nodes, methodCallInfo.MethodCallNamespace, NAMESPACE_INDEX);
        TreeNode typeNode = insertNode(nameSpaceNode.Nodes, methodCallInfo.MethodCallType, TYPE_INDEX);
        TreeNode methodNode = insertNode(typeNode.Nodes, methodCallInfo.MethodCallName, METHOD_INDEX);
      }

    }

    /// <summary>
    /// Inserts the node.
    /// </summary>
    /// <param name="node">The node.</param>
    /// <param name="p">The p.</param>
    /// <param name="iImageIndex">Index of the i image.</param>
    /// <returns></returns>
    private TreeNode insertNode(TreeNodeCollection nodes, string p, int iImageIndex)
    {
      TreeNode result = null;

      foreach (TreeNode child in nodes)
      {
        if (child.Text == p)
        {
          result = child;
          break;
        }
      }

      if (result == null)
      {
        result = new TreeNode(p);
        if (iImageIndex != -1)
        {
          result.ImageIndex = iImageIndex;
          result.SelectedImageIndex = iImageIndex;
        }
        nodes.Add(result);
      }
      return result;
    }

    private DTreeNode<object> createMethodCallTree(List<MethodCallInfo> methodCallList)
    {
      DTreeNode<object> dNode = new DTreeNode<object>("Method");

      Queue<MethodCallInfo> queueMethods = new Queue<MethodCallInfo>(methodCallList);
      if (queueMethods.Count > 0)
      {
        MethodCallInfo methodCallInfo = queueMethods.Peek();

        createMethodCallSubTree(methodCallInfo.MethodName,
                                        methodCallInfo.TypeName,
                                        dNode,
                                        queueMethods);
      }
      return dNode;
    }



    private void createMethodCallSubTree(string strMethodCall,
                                                 string strTypeCall,
                                                 DTreeNode<object> nodeCaller,
                                                 Queue<MethodCallInfo> queueMethods)
    {
      while (queueMethods.Count > 0)
      {
        MethodCallInfo methodCallInfo = queueMethods.Peek();

        if ((methodCallInfo.MethodName == strMethodCall) &&
          (methodCallInfo.TypeName == strTypeCall))
        {
          DTreeNode<object> child = new DTreeNode<object>(methodCallInfo);
          nodeCaller.Nodes.Add(child);
          queueMethods.Dequeue();
          createMethodCallSubTree(methodCallInfo.MethodCallName,
                                          methodCallInfo.MethodCallType,
                                          child,
                                          queueMethods);

        }
        else
        {
          break;
        }
      }

    }


    private void setVisibleMethodCallTree(DTreeNode<object> node, 
                                string strText, 
                                int iFilterType,
                                bool bShowOrHide,
                                bool bFilterCalls, 
                                StringBuilder sbResult)
    {
      foreach (DTreeNode<object> child in node.Nodes)
      {
        MethodCallInfo methodCallInfo = child.Value as MethodCallInfo;
        bool bMatch = false;
        string strMethodCallText = GetStrMethodCallText(iFilterType, methodCallInfo);

        bMatch = (string.Compare(strMethodCallText, strText) == 0);
        if(bMatch)
        {
          if(bFilterCalls)
          {
            setVisibleMethodCallSubTree(child, bShowOrHide, sbResult);
            // WARNING: Break structure
            return;
          }
          else
          {
            methodCallInfo.Visible = bShowOrHide;
            sbResult.AppendLine(string.Format("{0} : {1}", methodCallInfo.MethodCallName, methodCallInfo.MethodCallType));
          }
        }
        setVisibleMethodCallTree(child,
                                strText,
                                iFilterType,
                                bShowOrHide,
                                bFilterCalls,
                                sbResult);

      }

    }

    private string GetStrMethodCallText(int iFilterType, MethodCallInfo methodCallInfo)
    {
      string strMethodCallText = string.Empty;
      switch (iFilterType)
      {
        case ASSEMBLY_INDEX:
          strMethodCallText = methodCallInfo.TargetMethodAssembly;
          break;
        case NAMESPACE_INDEX:
          strMethodCallText = methodCallInfo.MethodCallNamespace;
          break;
        case TYPE_INDEX:
          strMethodCallText = methodCallInfo.MethodCallType;
          break;
        case METHOD_INDEX:
          strMethodCallText = methodCallInfo.MethodCallName;
          break;
      }
      return strMethodCallText;
    }

    private void setVisibleMethodCallSubTree(DTreeNode<object> node, bool bVisible, StringBuilder sbResult)
    {
      foreach(DTreeNode<object> child in node.Nodes)
      {
        MethodCallInfo methodCallInfo = child.Value as MethodCallInfo;
        methodCallInfo.Visible = bVisible;
        sbResult.AppendLine(string.Format("{0} : {1}", methodCallInfo.MethodCallName, methodCallInfo.MethodCallType));
        setVisibleMethodCallSubTree(child, bVisible, sbResult);
      }
    }

    private void commandFilterMethodCallTree(bool bVisible, bool bFilterCalls)
    {
      _richTextBox.Clear();

      if (_treeViewFilters.SelectedNode != null)
      {
        TreeNode selectedNode = _treeViewFilters.SelectedNode;
        StringBuilder sb = new StringBuilder();

        sb.AppendLine("Nodes:");

        setVisibleMethodCallTree(_root, selectedNode.Text, selectedNode.ImageIndex, bVisible, bFilterCalls, sb);
        _richTextBox.Text = sb.ToString();
        updateView();

      }
      
    }

    int countVisibleTreeNodes(DTreeNode<object> dNode)
    {
      int iCount = 0;
      MethodCallInfo methodCallInfo = dNode.Value as MethodCallInfo;
      if (methodCallInfo != null)
      {
        iCount = (methodCallInfo.Visible) ? 1 : 0;
      }

      foreach (DTreeNode<object> child in dNode.Nodes)
      {
        iCount += countVisibleTreeNodes(child);
      }
      return iCount;
    }

    private void updateView()
    {
      int iCount = countVisibleTreeNodes(_root);
      _lblVisibleNodes.Text = string.Format("N. Visibles {0}", iCount);
      _treeViewController.UpdateAllNodes();
    }

    private void _btnHide_Click(object sender, EventArgs e)
    {
      commandFilterMethodCallTree(false, false);
    }

    private void _btnHideCalls_Click(object sender, EventArgs e)
    {
      commandFilterMethodCallTree(false, true);
    }

    private void _btnShow_Click(object sender, EventArgs e)
    {
      commandFilterMethodCallTree(true, false);
    }

    private void _btnShowCalls_Click(object sender, EventArgs e)
    {
      commandFilterMethodCallTree(true, true);
    }

    private void _methodCallTreeView_AfterCheck(object sender, TreeViewEventArgs e)
    {
      if((e.Action == TreeViewAction.ByMouse) || (e.Action == TreeViewAction.ByKeyboard))
      {
        TreeNode tNode = e.Node;
        DTreeNode<object> dNode = _treeViewController.GetDataNode(tNode);
        MethodCallInfo methodCallInfo = dNode.Value as MethodCallInfo;
        if(methodCallInfo!=null)
        {
          methodCallInfo.Visible = tNode.Checked;
        }
        updateView();
      }
    }

    private void DlgFilterMethodCallTree_Load(object sender, EventArgs e)
    {
      updateView();
    }
  }
}
